package org.vectrics.skill;


import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

import org.apache.log4j.Category;
import org.vectrics.SystemException;
import org.vectrics.common.tree.TreeHelper;


public class SkillSetUtil implements java.io.Serializable {
    private static Category log = Category.getInstance(SkillSetUtil.class);
    private static Category clrBranchlog = Category.getInstance(SkillSetUtil.class.getName() 
    		+ "_clearBranchesOfUnratedChildren()");
    private SkillRatingSet skillRatingSet = null;
    //private Tree skillTree = null;
    private Skill rootSkill = null;

    public SkillSetUtil(SkillRatingSet skillRatingSet, Skill rootSkill) {
        this.skillRatingSet = skillRatingSet;
        this.rootSkill = rootSkill;
    }


    public Skill findSkill(String skillCode) {
        return((Skill)TreeHelper.findNode(rootSkill, skillCode));
    }
    
    /*
    public void addSkillRating(SkillRating iRating)
    {
        SkillRating rating = null;
        rating = skillRatingSet.findSkillRating(iRating.getSkill());
        if (rating == null) {
            
        }
        
        if (skillRatingSet.findSkillRating(iRating.getSkill()) {
            SkillRating existRating = getSkillRating(iRating.getSkill());
            if (iRating.getLevel() > 0)
                existRating.setLevel(iRating.getLevel());
            if (iRating.getYears() > 0)
                existRating.setLevel(iRating.getYears());
            if (iRating.getYes())
                existRating.setYes(iRating.getYes());
        };
    };
    */

    public void removeSkillsForLevel(int level) throws SkillException {
        log.debug("removeSkillsForLevel() called.");
        
        if (rootSkill == null) {
        	log.error("removeSkillsForLevel encountered a NULL root skill");
        	throw new SkillException("removeSkillsForLevel encountered a NULL root skill");
        }
        
        try {
        	
        	Collection childrenAtLevel = TreeHelper.getChildrenAtLevel(rootSkill, level);
        	if (childrenAtLevel == null) {
        		throw new SkillException("removeSkillsForLevel() - encountered a set of children which was null");
        	}
        	else {
		        Iterator iter = childrenAtLevel.iterator();
		        while (iter.hasNext()) {
		            Skill skill = (Skill)iter.next();
		            log.debug("removeSkillsForLevel() - looking for rating: " + skill.getCode());
		            skillRatingSet.removeSkillRating(skill);
		        }
        	}
        }
        catch (Exception ex) {
        	log.error("Exception occured while removing skills for level", ex);
        	throw new SkillException("Exception occured while removing skills for level", ex);
        }
        
    }
    


    public void clearSkillBranch(Skill skill) {
        skillRatingSet.removeSkillRating(skill);
        Iterator iter = skill.getChildren().iterator();
        while (iter.hasNext()) {
            Skill childSkill = (Skill)iter.next();
            clearSkillBranch(childSkill);
        };
    }

    public void removeBranch(Skill skill) {
        log.debug("removeBranch() - called");
        skillRatingSet.removeSkillRating(skill);
        Iterator iter = skill.getChildren().iterator();
        while (iter.hasNext()) {
            Skill childSkill = (Skill)iter.next();
            removeBranch(childSkill);
        }
    };

    public void clearBranchesOfUnratedParents(int level) {
        if (clrBranchlog.isDebugEnabled())
            clrBranchlog.debug("clearBranchesOfUnratedParents() called for level = " + level);
    
        Iterator iter = TreeHelper.getChildrenAtLevel(rootSkill, level).iterator();
        while (iter.hasNext()) {
            Skill skill = (Skill)iter.next();
            if (hasSkill(skill)) {
                if (clrBranchlog.isDebugEnabled())
                    clrBranchlog.debug("clearBranchesOfUnratedParents() - branch ok: " + skill.getDescription());
            }
            else {
                if (clrBranchlog.isDebugEnabled())
                    clrBranchlog.debug("clearBranchesOfUnratedParents() - removing branch: " + skill.getDescription());
                removeBranch(skill);    
            }

        }
    }
    
    
    // Parents of skill ratings are not saved in the database unless they 
    // need a rating themselves.  This function will add 'temporary ratings' 
    // for parents of skills the user has.
    public void addImpliedParentSkills() {
    	if (skillRatingSet == null) {
    		log.error("addImpliedParentSkills()- skillRatingSet is null");
    		throw new SystemException("addImpliedParentSkills()- skillRatingSet is null");
    	}
    	HashSet newParentSet = new HashSet();
        log.debug("addImpliedParentSkills() - called");
        try {
            Iterator iter = skillRatingSet.findAllSkillRatings().iterator();
            while (iter.hasNext()) {
                SkillRating rating = (SkillRating)iter.next();
                log.debug("addImpliedParentSkills() - 1.0");
                Skill skill = rating.getSkill();
                // Make sure all parents of skill have rating entry.
                Skill parent = skill.getSkillParent();
                log.debug("addImpliedParentSkills() - 2.0");
                while ((parent != null) && (parent.getCode().equals(Skill.ROOT_SKILL_CODE) == false)) {
                    log.debug("addImpliedParentSkills() - 3.1  parent = " + parent.getCode());
                    if (this.hasSkill(parent) == false) {
                        SkillRating newRating = skillRatingSet.findSkillRating(findSkill(parent.getCode()));
                        if (newRating == null) {
                            newRating = skillRatingSet.createSkillRating(findSkill(parent.getCode()));
                        }
    
                        newRating.setSkill(parent);
                        newRating.setLevel("y");
                        newParentSet.add(newRating);
                    }
                    else {
                        log.debug("addImpliedParentSkills() - already has skill.");
                    }
                    parent = parent.getSkillParent();
                    log.debug("addImpliedParentSkills() - 4.0 changing parent to " + parent.getCode());
                }
                
            }
            log.debug("addImpliedParentSkills() - finished");
        }
        catch (Exception ex) {
            log.error("Exception in addImpliedParentSkills() ", ex);
        }
        this.skillRatingSet.addAll(newParentSet);
    }

    synchronized public void clearImpliedParentSkills() {
        /*
        Iterator iter = this.iterator();
        HashSet deleteList = new HashSet();
        while (iter.hasNext()) {
            SkillRating rating = (SkillRating)iter.next();
            if (rating.getSkill().getNeedsRating() == false) {
                deleteList.add(rating);
            }
        }
        this.removeAll(deleteList);
        */
    }
    
    
    public boolean hasSkill(Skill iSkill) {
        boolean result = false;
        SkillRating skillRating = skillRatingSet.findSkillRating(iSkill);
        if (skillRating != null) {
            result = true;
        }
        return(result);
    };

    // Return TRUE if user has iSkill or any skill under the branch of iSkill.
    public boolean hasSkillRatingInBranch(Skill iSkill) {
        boolean result = false;
        //Check skill itself
        result = hasSkill(iSkill);

        log.debug("Check children of passed skill, to see if any ratings");
        Iterator iter = iSkill.getChildren().iterator();
        while ((result == false) && (iter.hasNext())) {
            Skill child = (Skill)iter.next();
            // Recurse with child skill
            result = hasSkillRatingInBranch(child);
        };
        return(result);
    }

    
    public void clearUnrated()
    {
        log.debug("clearUnrated() called.");
        /*
        Iterator iter = iterator();
        while (iter.hasNext()) {
            SkillRating rating = (SkillRating)iter.next();
            if (rating.hasSkill() == false) {
                log.debug("removing: " + rating.getSkill().getSkillCode());
                remove(rating);
                iter = iterator();
            };
        }
        */
    };

    public String toString() {
    	log.debug("toString() - method to display this skill set as a string - good for debugging");
        StringBuffer str = new StringBuffer();
        try {
	        str.append("UserSkillList\n");
	        Iterator iter = skillRatingSet.findAllSkillRatings().iterator();
	        while (iter.hasNext()) {
	            SkillRating rating = (SkillRating)iter.next();
	            str.append("  " + rating.getSkill().getCode() + " - " + rating.getLevel()+ "/" + rating.hasSkill() + "\n");
	        };
        }
        catch (Exception ex) {
        	log.error("Exception in toString()", ex);
        }
        return(str.toString());
    }

}